#coding=utf-8
#
# Copyright (C) 2014  NianNian TECH Co., Ltd. All rights reserved.
# Created on Jul 25, 2014, by Junn
#
from core.models import BaseModel
from django.db import models
from regards.managers import RegardManager, DateTipManager, RegardMessageManager,\
    SystemMsgManager
from utils import logs
from django.utils import timezone
from users.models import User
from messages.models import PushMessage
from core.push import push_to_all, push_to_single
import datetime


REGARD_TYPE_CHOICES = (
    ('S', u'简单语音'),
    ('C', u'语音贺卡'),
    ('M', u'音乐问候'),
)

REGARD_STATUS_CHOICES = (
    ('S', u'已发送'),
    ('C', u'新创建'),
)

class Regard(BaseModel):
    '''问候数据模型. 包括: 语音问候, 贺卡(图/文/语音), 音乐问候等'''
    
    author = models.ForeignKey('users.User',    related_name='author', verbose_name=u'发布者')
    receiver = models.ForeignKey('users.User',  related_name='receiver', verbose_name=u'问候接收者')
    
    #修改为可空, 因问候发送可不在同一家庭进行. 该字段被弃用
    family = models.ForeignKey('families.Family', verbose_name=u'所属家庭', null=True, blank=True)
         
    info = models.CharField(max_length=150, null=True, blank=True, verbose_name=u'文字', default='')
    pic = models.CharField(verbose_name=u'图片', max_length=80, null=True, blank=True, default='')
    aud = models.CharField(verbose_name=u'语音', max_length=80, null=True, blank=True, default='')
    aud_len = models.IntegerField(u'语音长度', null=True, blank=True, default=0)       #单位秒
    
    sent_time = models.DateTimeField(u'发送时间', default=timezone.now) # 问候发送时间, 默认为条目创建时间
    status = models.CharField(u'状态', max_length=1, choices=REGARD_STATUS_CHOICES, default='C') #问候当前状态, 已发送/新创建
    is_checked = models.BooleanField(u'已读', default=False)               #接收者是否已读
    is_sent_now = models.BooleanField(u'立即发送', default=True)            #是否立即发送
    
    type = models.CharField(u'类型', max_length=1, choices=REGARD_TYPE_CHOICES, default='S')  #问候类型, 简单语音/语音贺卡
    
    # 建立双向链表, 可以方便查找问候回复关系链
    reply_to = models.ForeignKey('self', related_name='rep_to', verbose_name=u'回复目标', null=True, blank=True, )  #不能使用reply_to作为related_name, 下同
    reply_by = models.ForeignKey('self', related_name='rep_by', verbose_name=u'回复源', null=True, blank=True, )
    
    objects = RegardManager()
    
    class Meta:
        verbose_name = u'问候'
        verbose_name_plural = u'问候'
        app_label = 'regards'
        
    def __unicode__(self):
        return u'%s, %s' % (self.id, self.type)
    
    def get_reply(self):
        '''返回问候的相应的回复数据'''
        if self.type != 'R':
            return self.objects.filter(author=self.receiver, receiver=self.author, type='R')[0]
        return None
    
    def send(self):  
        ## push message
        try:
            nrmsg, created = NewRegardMessage.objects.get_or_create(
                sender=self.author_id, 
                receiver=self.receiver_id,
            )
            nrmsg.set_extra_info(1, 'R', u'[问候]', self.sent_time)
        except Exception, e:
            logs.warn(e)
            pass    
        
        self.status = 'S'  #放入消息列表后, 问候状态更新
        self.save()
        #s_regard_waitlist_push.send(sender=Regard, waitlist=self)
    
    def check(self):
        self.is_checked = True
    
    def is_sent(self):
        return self.status == 'S'
    
    def reply(self, reply_to):
        '''回复某问候'''
        
        try:
            to_obj = Regard.objects.get(id=int(reply_to))
            if to_obj.reply_by:
                cause = u'问候已被回复: %s' % reply_to
                logs.error(cause)
                return False, cause
            to_obj.reply_by = self
            to_obj.save()
            self.reply_to = to_obj
            self.save()
            return True, ''
        except Exception, e:
            logs.error(e)
        return False, u'Add new regard reply to %s exception ' % reply_to    
    
    def is_reply(self):
        '''是否为一个回复'''
        return self.reply_to
    
    def to_json(self):
        '''RegardSerializer中的reply_to对象json化时, 存在递归转化, 因未找到处理方法. 暂用该方法代替'''
        author = User.objects.get_cached(self.author_id)
        receiver = User.objects.get_cached(self.receiver_id)
        return {
            "id": self.id,
            "author": self.author_id,
            "receiver": self.receiver_id,
            "author_nickname": author.nickname if author else '',
            "author_avatar": author.avatar if author else '',
            "receiver_avatar": receiver.avatar if receiver else '',
            "receiver_nickname": receiver.nickname if receiver else '',
            "info": self.info,
            "pic": self.pic if self.pic else '',
            "aud": self.aud if self.aud else '',
            "aud_len": self.aud_len,
            "created_time": normalize_time(self.created_time),
            "type": self.type,
            "sent_time": normalize_time(self.sent_time),
            "status": self.status,
            "is_sent_now": self.is_sent_now,
            "is_checked": self.is_checked                      
        }
        
def normalize_time(dtime):
    return dtime if isinstance(dtime, unicode) else dtime.strftime('%Y-%m-%d %H:%M:%S')
   

        
class DateTip(BaseModel): 
    '''事件提醒'''   
    
    creator = models.ForeignKey('users.User', related_name='creator', verbose_name=u'添加人')
    title = models.CharField(u'标题', max_length=30)
    spec_date = models.DateTimeField(u'事件时间')  #事件日期与时间合在一起
    notice_type = models.SmallIntegerField(u'提醒设置', default=0) #0-当天提醒, 1-提前1天提醒, 3-提醒3天提醒, ...
    related_buddy = models.ForeignKey('users.User', related_name='related_buddy', null=True, blank=True, verbose_name=u'提醒关联人') #如提醒为:老妈生日, 则该属性关联老妈的用户id
    desc = models.CharField(u'事件描述', max_length=80, null=True, blank=True, default='')
    
    #若提醒消息已加入消息队列, 则置为True. 表示提醒已触发
    is_triggered = models.BooleanField(u'是否已触发', default=False)
    is_checked = models.BooleanField(u'是否已处理', default=False)   #提醒触发后, 用户查看提醒或做其他操作将该标识置为True
    
    objects = DateTipManager()
        
    class Meta:
        verbose_name='事件提醒'
        verbose_name_plural = u'事件提醒'   
        ordering = ['spec_date']
        
    def __unicode__(self):
        return u'%s' % self.title    
    
    def is_triggerd_expired(self):
        '''触发时间是否已过期'''
        if datetime.datetime.now() + datetime.timedelta(days=self.notice_type) >= self.spec_date: 
            return True
        return False
    
    def init_status(self):
        '''initialize datetip status'''
        self.is_triggered = False
        self.is_checked = False
    
#系统消息类型   
SYS_MSG_CHOICES = (
    ('S1', u'系统通知'),    #所有用户均会收到该通知 
    ('S2', u'用户通知'),    #发给某特定用户的系统消息
)    
    
class SystemMsg(BaseModel): 
    '''系统消息
    
    系统消息内容体
    '''   
    
    title = models.CharField(u'标题', max_length=50, default='')
    desc =  models.TextField(u'消息内容', max_length=140, default='')
    receiver = models.ForeignKey('users.User', verbose_name=u'接收人', null=True, blank=True) #为空时表示为全部接收人
    type = models.CharField(u'类型', max_length=2, choices=SYS_MSG_CHOICES, default='S1')
    is_checked = models.BooleanField(u'是否已读', default=False)
    
    objects = SystemMsgManager()
        
    class Meta:
        verbose_name='系统消息'
        verbose_name_plural = u'系统消息'   
        ordering = ['-created_time']
        
    def __unicode__(self):
        return u'%s' % self.title
    

#消息类型   
MSG_TYPE_CHOICES = (
    ('R', u'(R)问候消息'),
    ('T', u'(T)提醒消息'),
    ('S', u'(S)系统消息'),
)    

class NewRegardMessage(BaseModel):
    '''消息队列模型. 用于存放等待推送的问候/提醒/系统消息, 该模型不存放消息所关联的具体实体内容.
    
    TODO: 考虑未推送成功的消息 有一个累积错误次数. 当错误累积到一定次数, 永久停止推送 
    '''
    
    sender = models.IntegerField(u'发送者')
    receiver = models.IntegerField(u'接收者', null=True, blank=True, default=0) #为0时表示接收者为全部用户
    count = models.IntegerField(default=0)       #未读新问候消息计数, count值仅在新问候被读取时清0
    msg_type = models.CharField(u'消息类型', max_length=1, choices=MSG_TYPE_CHOICES, default='R')
    is_pushed = models.BooleanField(default=False)      #若消息已被推送或被拉用户拉取, 则置为True
    updated_time = models.DateTimeField(auto_now=True)  #已有数据记录被更新时间
    
    #消息推送错误次数, 达到一定计数后未推送成功消息将停止被推送, 每隔几小时后该计数清0, 以重新启动推送
    pushed_err_count = models.IntegerField(default=0)
    
    #最新一条问候/提醒消息内容, 有语音则优先显示[语音], 否则[图片]或文字内容
    item_content = models.CharField(u'最新消息内容', max_length=150, default='')
    item_time = models.DateTimeField(u'最新消息发生时间', null=True, blank=True)  
    
    #note = models.CharField(u'备注', max_length=40, default='')
    
    objects = RegardMessageManager()
    
    class Meta:
        verbose_name = u'Q消息队列'
        verbose_name_plural = u'Q消息队列'
        ordering = ['-item_time']
        
    def __unicode__(self):
        return u'%s, %s, %s, %s' % (self.id, self.sender, self.receiver, self.count)
         
    def is_sys_msg(self):
        '''是否系统消息'''
        return self.msg_type == 'S'
    
    def push(self):
        '''将消息推送到远端推送服务器(如jpush)'''
        
        sender = User.objects.get_cached(self.sender)
        extras = {
            'sender':           sender.id, 
            'sender_nickname':  sender.nickname,
            'sender_avatar':    sender.avatar,
            'count':            self.count, 
            
            'item_content': self.item_content,  #最新一条消息内容
            'item_time':    str(self.item_time)
        }
        pm = PushMessage(self.msg_type, self.item_content, extras=extras)
        if self.is_sys_msg():
            if push_to_all(pm):
                self.set_pushed()
            else:
                self.incr_pushed_err_count()            
        else:
            if push_to_single(self.receiver, pm):
                self.set_pushed()
            else:
                self.incr_pushed_err_count()
                
    def set_extra_info(self, count, msg_type, item_content, item_time):  
        '''设置待推送消息的其他属性值''' 
        self.is_pushed = False
        self.count += count
        self.msg_type = msg_type
        self.item_content = item_content
        self.item_time = item_time
        self.save()
                                           
    def set_pushed(self):
        self.is_pushed = True
        self.pushed_err_count = 0
        self.save()
        
    def incr_pushed_err_count(self):
        self.pushed_err_count += 1
        self.save()        
    
# class TodayDateTip(BaseModel): 
#     '''事件提醒临时表.  TODO: 暂未使用, 后续调整
#     该表中存放当天需要提醒的事件数据. 在每天的00:00时间将所有当天需要触发的数据从DateTip取到该临时表
#     '''   
#     
#     creator = models.ForeignKey('users.User', related_name='creator', verbose_name=u'提醒添加人')
#     title = models.CharField(u'名称', max_length=30)
#     spec_date = models.DateTimeField(u'节日具体时间')  #事件日期与时间合在一起
#     notice_type = models.SmallIntegerField(u'提醒设置', default=0) #0-当天提醒, 1-提前1天提醒, 3-提醒3天提醒, ...
#     related_buddy = models.ForeignKey('users.User', related_name='related_buddy', null=True, blank=True, verbose_name=u'提醒关联人') #如提醒为:老妈生日, 则该属性关联老妈的用户id
#     desc = models.CharField(u'日期描述', max_length=80, null=True, blank=True, default='')
#     
#     #若提醒消息已加入消息队列, 则置为True. 表示提醒已触发
#     is_triggered = models.BooleanField(u'提醒是否已触发', default=False)  
#     
#     objects = DateTipManager()
#         
#     class Meta:
#         verbose_name='事件提醒'
#         verbose_name_plural = u'事件提醒'   
#         ordering = ['spec_date']
#         
#     def __unicode__(self):
#         return u'%s' % self.title      
